
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\core\core.hpp>
#include "Utils.h"

cv::Mat ExtraiSegmento(const cv::Mat&img,const int seg_index,const cv::Rect& roi = cv::Rect())
{
	cv::Mat imOut (img.size(),0);

	
	for( int y = 0; y < img.rows; y++ )
	{
		for( int x = 0; x < img.cols; x++ )
		{
			//if(seg_index==img.at<uchar>(cv::Point(x,y)))
			{
				imOut.at<uchar>(cv::Point(x,y)) = (seg_index==img.at<uchar>(cv::Point(x,y)))?255:0;
			}

		}
	}

	return imOut;
}


cv::Mat CalculaKMedias(const cv::Mat&img,const int clusterCount,const int attempts)//,cv::Mat&imIndexes)//,cv::Mat &bestLabels,cv::Mat &centers)
{	
	//int clusterCount = 10;
	cv::Mat labels;
	//int attempts = 5;
	cv::Mat bestLabels, centers;
	cv::Mat samples(img.rows * img.cols, 3, CV_32F);
	
	for( int y = 0; y < img.rows; y++ )
		for( int x = 0; x < img.cols; x++ )
			for( int z = 0; z < 3; z++)
				samples.at<float>(y + x*img.rows, z) = img.at<cv::Vec3b>(y,x)[z];

	cv::kmeans(samples,clusterCount,bestLabels,cv::TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 0.0001, 10000), attempts, cv::KMEANS_PP_CENTERS, centers );

	cv:: Mat imgOut( img.size(), img.type() );
	cv::Mat imIndexes(img.size(),0);
	for( int y = 0; y < img.rows; y++ )
	{
		for( int x = 0; x < img.cols; x++ )
		{
			int cluster_idx = bestLabels.at<int>(y + x*img.rows,0);

			//if(cluster_idx!= color)continue;

			imIndexes.at<uchar>(cv::Point(x,y)) = cluster_idx;

			imgOut.at<cv::Vec3b>(y,x)[0] = centers.at<float>(cluster_idx, 0);
			imgOut.at<cv::Vec3b>(y,x)[1] = centers.at<float>(cluster_idx, 1);
			imgOut.at<cv::Vec3b>(y,x)[2] = centers.at<float>(cluster_idx, 2);
		}
	}

	//cv::imshow("x",imIndexes*20);
	//cv::waitKey();
	return imIndexes;

}

void CalculaHistogramas(const cv::Mat &img,const cv::Rect &roi,int *histFull,int *histRoi,int *histDiff,const int histSize)
{
	std::fill(histFull,histFull + histSize,0);
	std::fill(histRoi,histRoi + histSize,0);
	std::fill(histDiff,histDiff + histSize,0);
	
	for( int y = 0; y < img.rows; y++ )
	{
		for( int x = 0; x < img.cols; x++ )
		{
			int cluster_idx = img.at<uchar>(cv::Point(x,y));				  
			
			histFull[cluster_idx]++;

			if(x >=roi.x && x <= roi.x + roi.width && y >= roi.y && y <=roi.y + roi.height)
			{
				histRoi[cluster_idx]++;
			}
		}
	}

	for(int i = 0; i < histSize;i++)
	{
		histDiff[i] = histFull[i] - histRoi[i];
	}
}



int AnalisaHistogramas(const cv::Rect roi,int *histDiff,const int *histFullIm,const int *histRoi, const int histSize)
{
	for(int i = 0 ; i < histSize;i++)
	{
		const int roiArea =  roi.width*roi.height;
		if(histRoi[i] < roiArea* 0.2)//|| hist[i] > roiArea * 0.9)
		{
			histDiff[i] =INT_MAX;
		}
	}
			
	int index = std::min_element(histDiff,histDiff+histSize) - histDiff;
				
	return index;


}
cv::Mat Segmentacao(const cv::Mat& im,const cv::Rect & roi)
{
	cv::Mat imProc,imTmp;
	cv::GaussianBlur(im,imTmp,cv::Size(3,3),1);

	cv::cvtColor(imTmp,imProc,CV_BGR2Lab);
	//imProc = imTmp;

	const int clusters = 8;
	const int attempts = 5;
	imProc = ::CalculaKMedias(imProc,clusters,attempts);


	int histFull[clusters];//histograma de cores da imagem inteira
	int histRoi[clusters];//histograma de cores na roi onde estao os caracteres
	int histDiff[clusters];//diferenca entre os dois histogramas
		
	CalculaHistogramas(imProc,roi,histFull,histRoi,histDiff,clusters);

	int segIndex = AnalisaHistogramas(roi,histDiff,histFull,histRoi,clusters);
	
	imProc =::ExtraiSegmento(imProc,segIndex);

	//static int cont = 0 ;	
	//cv::imwrite("d:\\"+Utils::to_string(cont)+".bmp",imProc);
	//cont ++;
	return imProc;
}
